#pragma once

#include "inference_engine.hpp"

namespace plugin {
  
  class callback_t {
  protected:
    literal_vector_t         &m_hypotheses;
    ilp::solver_t            &m_ilp_solver;
    ie::weighted_abduction_t &m_ie;
    ie::variable_cluster_t   &m_vc;
  public:
    callback_t( ie::weighted_abduction_t &ie ) : m_ie( ie ), m_hypotheses( ie.m_hypotheses ), m_vc( ie.m_vc ), m_ilp_solver( ie.m_ilp_solver ) {}
    virtual bool process() = 0;
  };

  class conditional_unification_t : public callback_t {
    
    vector<kb::pps_template_t> m_regex_cups;
    ssl_dict_t                 m_regex_cache;
    
  public:
    typedef unordered_map<ilp::variable_t, unordered_map<int, ilp::variable_set_t> > cset_t;
    
    conditional_unification_t( ie::weighted_abduction_t& );
    bool process();
    bool generate_constraint( cset_t*, unifier_operator_t&, string_list_t&, int, bool = false );
    bool is_conditioned_predicate( string_list_t*, const string& );
  };

  class xor_constraint_t : public callback_t {
  public:
    xor_constraint_t( ie::weighted_abduction_t& ie ) : callback_t( ie ) {}
    bool process();
  };

  class prohibit_same_multiple_explanations_t : public callback_t {
  public:
    prohibit_same_multiple_explanations_t( ie::weighted_abduction_t& ie ) : callback_t( ie ) {}
    bool process();
  };

  class prohibit_circular_zero_t : public callback_t {
  private:
    void _apply_circular_zero_blocking( int_set_t &expl, int_set_t &conseq, ilp::variable_t var_unifier_operator, literal_t &h );
    
  public:
    prohibit_circular_zero_t( ie::weighted_abduction_t& ie ) : callback_t( ie ) {}
    bool process();
  };
  
}
